package com.example.fms.service.impl;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.func.LambdaUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.fms.constant.ChineseConstant;
import com.example.fms.constant.NumberConstant;
import com.example.fms.dto.req.ArithmeticInfoReqDto;
import com.example.fms.entity.ArithmeticLogInfo;
import com.example.fms.entity.MinOrderRule;
import com.example.fms.entity.StandardFreightRule;
import com.example.fms.enums.CalculationRulesEnum;
import com.example.fms.exception.BusinessException;
import com.example.fms.exception.ExceptionEnum;
import com.example.fms.mapper.ArithmeticLogInfoMapper;
import com.example.fms.mapper.MinOrderRuleMapper;
import com.example.fms.mapper.StandardFreightRuleMapper;
import com.example.fms.service.ArithmeticLogInfoService;
import com.example.fms.service.MinOrderRuleService;
import com.example.fms.service.StandardFreightRuleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;


@Service
@Slf4j
public class ArithmeticLogInfoServiceImpl extends ServiceImpl<ArithmeticLogInfoMapper, ArithmeticLogInfo> implements ArithmeticLogInfoService {
    @Resource
    private MinOrderRuleMapper minOrderRuleMapper;

    @Resource
    MinOrderRuleService minOrderRuleService;

    @Resource
    StandardFreightRuleService standardFreightRuleService;

    @Resource
    private ArithmeticLogInfoMapper arithmeticLogInfoMapper;
    @Resource
    private ArithmeticLogInfoService arithmeticLogInfoService;

    @Resource
    private StandardFreightRuleMapper standardFreightRuleMapper;

    @Override
    public Map<String, Integer> getArithmeticInfo(ArithmeticInfoReqDto req) {
        //创建日志保存信息
        ArithmeticLogInfo arithmeticLogInfo = new ArithmeticLogInfo();
        //将req赋给arithmeticLogInfo
        BeanUtils.copyProperties(req, arithmeticLogInfo);

        Map<String, Integer> arithmeticInfoMap = new HashMap<>();
        // 判断最小数量计算规则
        LambdaQueryWrapper<MinOrderRule> minOrderQw = Wrappers.lambdaQuery();
        minOrderQw.eq(MinOrderRule::getWarehouse, req.getWarehouse())
                .eq(MinOrderRule::getType, req.getType())
                .eq(MinOrderRule::getProvince, req.getProvince())
                .in(MinOrderRule::getCity, req.getCity(), ChineseConstant.NULL)
                .in(MinOrderRule::getArea, req.getArea(), ChineseConstant.NULL);
        List<MinOrderRule> minOrderRules = minOrderRuleMapper.selectList(minOrderQw);

        if (CollectionUtil.isEmpty(minOrderRules)) {
            throw new BusinessException(ExceptionEnum.MIN_CONFLICT_IS_NUll);
        }

        MinOrderRule minOrderRule = minOrderRules.get(0);
        if (req.getNumber() < minOrderRule.getMinOrder()) {
            // 判断标准运费规则
            LambdaQueryWrapper<StandardFreightRule> standardFreightQw = Wrappers.lambdaQuery();
            standardFreightQw.eq(StandardFreightRule::getWarehouse, req.getWarehouse())
                    .eq(StandardFreightRule::getType, req.getType())
                    .eq(StandardFreightRule::getProvince, req.getProvince())
                    .in(StandardFreightRule::getCity, req.getCity(), ChineseConstant.NULL)
                    .in(StandardFreightRule::getArea, req.getArea(), ChineseConstant.NULL);
            List<StandardFreightRule> standardFreightRules = standardFreightRuleMapper.selectList(standardFreightQw);

            if (CollectionUtil.isEmpty(standardFreightRules)) {
                throw new BusinessException(ExceptionEnum.STANDARD_CONFLICT_IS_NUll);
            }

            for (StandardFreightRule s : standardFreightRules) {
                //发货数
                int numberOfShipments = req.getNumber();
                //规则订单数
                int number = Integer.parseInt(s.getNumber());
                //规则单价
                int freightUnitPrice = Integer.parseInt(s.getFreightUnitPrice());
                //范围
                String extent = s.getExtent();

                //如果订单数大于发货数，并且范围是大于等于，或者，订单数小于发货数并且范围是小于且等于
                boolean isNumberOfShipmentsCondition = (number >= numberOfShipments && (Objects.equals(extent, NumberConstant.TWO) || Objects.equals(extent, NumberConstant.THREE))) ||
                        (number <= numberOfShipments && (Objects.equals(extent, NumberConstant.ZERO) || Objects.equals(extent, NumberConstant.ONE)));

                if (isNumberOfShipmentsCondition) {
                    if (s.getCalculationRules().equals(CalculationRulesEnum.STRIP.getCode())) {
                        int freight = numberOfShipments * freightUnitPrice;
                        // 返回固定费用
                        arithmeticInfoMap.put(req.getOrderNumber(), freight);
                        //添加日志
                        arithmeticLogInfo.setArithmeticType(CalculationRulesEnum.STRIP.getCode());
                    } else if (s.getCalculationRules().equals(CalculationRulesEnum.FIXATION.getCode())) {
                        // 返回固定费用
                        arithmeticInfoMap.put(req.getOrderNumber(), freightUnitPrice);
                        //添加日志
                        arithmeticLogInfo.setArithmeticType(CalculationRulesEnum.FIXATION.getCode());
                    }
                }
            }
            if (CollectionUtil.isEmpty(arithmeticInfoMap)) {
                throw new BusinessException(ExceptionEnum.STANDARD_CONFLICT_IS_NUll);
            }
        } else {
            // 返回固定费用
            arithmeticInfoMap.put(req.getOrderNumber(), minOrderRule.getFixedCost());
            arithmeticLogInfo.setArithmeticType(CalculationRulesEnum.FIXATION.getCode());
        }
        //添加日志
        arithmeticLogInfo.setMoney(String.valueOf(arithmeticInfoMap.get(req.getOrderNumber())));
        arithmeticLogInfoMapper.insert(arithmeticLogInfo);
        return arithmeticInfoMap;
    }

    @Override
    public Map<String, String> getArithmeticInfoList(List<ArithmeticInfoReqDto> req) {
        List<ArithmeticLogInfo> arithmeticLogInfoList = new ArrayList<>();
        Map<String, String> arithmeticInfoListMap = new HashMap<>();
        //获取req中所有的省集合
        List<String> provinceList = req.stream().map(ArithmeticInfoReqDto::getProvince).toList();
        //获取req中所有的发货仓库集合
        List<String> warehouseList = req.stream().map(ArithmeticInfoReqDto::getWarehouse).toList();
        //创建最小查询qw
        LambdaQueryWrapper<MinOrderRule> minOrderQw = Wrappers.lambdaQuery();
        minOrderQw.in(MinOrderRule::getProvince, provinceList)
                .in(MinOrderRule::getWarehouse, warehouseList);
        //创建标准查询qw
        LambdaQueryWrapper<StandardFreightRule> standardFreightQw = Wrappers.lambdaQuery();
        standardFreightQw.in(StandardFreightRule::getProvince, provinceList)
                .in(StandardFreightRule::getWarehouse, warehouseList);

        //获取所有最小计算规则
        List<MinOrderRule> minOrderRuleList = minOrderRuleService.list(minOrderQw);
        //标准计算规则
        List<StandardFreightRule> standardFreightRuleList = standardFreightRuleService.list(standardFreightQw);

        req.forEach(s -> {
                    //创建日志保存信息
                    ArithmeticLogInfo arithmeticLogInfo = new ArithmeticLogInfo();
                    //将req赋给arithmeticLogInfo
                    BeanUtils.copyProperties(s, arithmeticLogInfo);
                    //过滤最小运费规则
                    List<MinOrderRule> filteredList = minOrderRuleList.stream()
                            .filter(rule -> Objects.equals(rule.getWarehouse(), s.getWarehouse()))
                            .filter(rule -> Objects.equals(rule.getType(), s.getType()))
                            .filter(rule -> Objects.equals(rule.getProvince(), s.getProvince()))
                            .filter(rule -> Objects.equals(rule.getCity(), s.getCity()) || Objects.equals(rule.getCity(), ChineseConstant.NULL))
                            .filter(rule -> Objects.equals(rule.getArea(), s.getArea()) || Objects.equals(rule.getArea(), ChineseConstant.NULL))
                            .toList();

                    if (CollectionUtil.isEmpty(filteredList)) {
                        arithmeticInfoListMap.put(s.getOrderNumber(), ChineseConstant.MIN_CONFLICT_IS_NUll);
                    } else {
                    MinOrderRule minOrderRule = filteredList.get(0);

                    if (s.getNumber() < minOrderRule.getMinOrder()) {
                        //过滤标准运费规则
                        List<StandardFreightRule> standardFreightRulefilterList = standardFreightRuleList.stream()
                                .filter(rule -> Objects.equals(rule.getWarehouse(), s.getWarehouse()))
                                .filter(rule -> Objects.equals(rule.getType(), s.getType()))
                                .filter(rule -> Objects.equals(rule.getProvince(), s.getProvince()))
                                .filter(rule -> Objects.equals(rule.getCity(), s.getCity()) || Objects.equals(rule.getCity(), ChineseConstant.NULL))
                                .filter(rule -> Objects.equals(rule.getArea(), s.getArea()) || Objects.equals(rule.getArea(), ChineseConstant.NULL))
                                .toList();

                        for (StandardFreightRule standardFreightRule : standardFreightRulefilterList) {
                            //发货数
                            int numberOfShipments = s.getNumber();
                            //规则订单数
                            int number = Integer.parseInt(standardFreightRule.getNumber());
                            //规则单价
                            Integer freightUnitPrice = Integer.parseInt(standardFreightRule.getFreightUnitPrice());
                            //范围
                            String extent = standardFreightRule.getExtent();

                            //如果订单数大于发货数，并且范围是大于等于，或者，订单数小于发货数并且范围是小于且等于
                            boolean isNumberOfShipmentsCondition = (number >= numberOfShipments && (Objects.equals(extent, NumberConstant.TWO) || Objects.equals(extent, NumberConstant.THREE))) ||
                                    (number <= numberOfShipments && (Objects.equals(extent, NumberConstant.ZERO) || Objects.equals(extent, NumberConstant.ONE)));


                            if (isNumberOfShipmentsCondition) {
                                if (standardFreightRule.getCalculationRules().equals(CalculationRulesEnum.STRIP.getCode())) {
                                    int freight = numberOfShipments * freightUnitPrice;
                                    // 返回固定费用
                                    arithmeticInfoListMap.put(s.getOrderNumber(), String.valueOf(freight));
                                    arithmeticLogInfo.setArithmeticType(CalculationRulesEnum.STRIP.getCode());
                                } else if (standardFreightRule.getCalculationRules().equals(CalculationRulesEnum.FIXATION.getCode())) {
                                    // 返回固定费用
                                    arithmeticInfoListMap.put(s.getOrderNumber(), String.valueOf(freightUnitPrice));
                                    arithmeticLogInfo.setArithmeticType(CalculationRulesEnum.FIXATION.getCode());
                                }
                            }
                        }
                        if (CollectionUtil.isEmpty(arithmeticInfoListMap)) {
                            arithmeticInfoListMap.put(s.getOrderNumber(), ChineseConstant.STANDARD_CONFLICT_IS_NUll);
                        }
                    } else {
                        // 返回固定费用
                        arithmeticInfoListMap.put(s.getOrderNumber(), String.valueOf(minOrderRule.getFixedCost()));
                        arithmeticLogInfo.setArithmeticType(CalculationRulesEnum.FIXATION.getCode());
                    }
                }
            arithmeticLogInfo.setMoney(String.valueOf(arithmeticInfoListMap.get(s.getOrderNumber())));
            arithmeticLogInfoList.add(arithmeticLogInfo);
        });
        //插入全部
        arithmeticLogInfoService.saveBatch(arithmeticLogInfoList);
        return arithmeticInfoListMap;
    }
}
